/**
 * 所有版权归 广西梧州 陈锦韬 所有
 *
 * @Title: RxAuthorizationServer
 * @Package com.rx.core.bean
 * @Description: 授权服务器
 * @author: 陈锦韬
 * @date: 2021\6\23 0023
 * @version V1.0
 * @Copyright: 2021 陈锦韬  All rights reserved.
 */
package com.rx.core.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.Arrays;

/**
 * @author: Administrator
 * @Description: 授权服务器
 * @date: 2021\6\23 0023
 */
@Configuration
@EnableAuthorizationServer
@Order(100)
public class RxAuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;


    @Autowired
    private TokenStore tokenStore;

    @Autowired
    @Qualifier("clientDetailsServices")
    private ClientDetailsService clientDetailsService;

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 授权码保存在内存。
     * @return
     */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource){
        //return new InMemoryAuthorizationCodeServices();
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Bean
    public AuthorizationServerTokenServices tokenServices(){
        DefaultTokenServices services = new DefaultTokenServices();
        // 客户端信息
        services.setClientDetailsService(clientDetailsService);
        // 刷新令牌
        services.setSupportRefreshToken(true);
        // 令牌存储策略
        services.setTokenStore(tokenStore);
        // JWT 令牌增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
        services.setTokenEnhancer(tokenEnhancerChain);

        // jwt  ........
        // 令牌有效期
        services.setAccessTokenValiditySeconds(7200);
        // 刷新令牌默认有效期
        services.setRefreshTokenValiditySeconds(259200);
        return services;
    }

    /**
     * 安全约束
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 授权端点：/oauth/authorize
        // 令牌端点：/oauth/token
        // 授权服务错误信息端点：/oauth/error
        // 确认授权提交：/oauth/confirm_access
        // 令牌 /oauth/token_key
        security.tokenKeyAccess("permitAll()")
                // 校验令牌 /oauth/check_token
                .checkTokenAccess("permitAll()")
                // 表单
                .allowFormAuthenticationForClients()
        ;
        //super.configure(security);
    }

    @Bean
    public ClientDetailsService clientDetailsServices(DataSource dataSource) {
        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService)clientDetailsService).setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

    /**
     * 客户端配置（给谁发令牌）
     * // 分配客户端ID及秘钥。
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置客户端。配置。可以放到数据库
        clients.withClientDetails(clientDetailsService);
//        // 内存。
//        clients.inMemory().withClient("c1")
//                .secret(new BCryptPasswordEncoder().encode("secret"))
//                //.secret("secret")
//                //有效时间 2小时 $2a$10$ginB5iTVAsJPQg9rwPXCSuHLA2U995JbQ.BXC3m7bv/Fujtuxj2p2
//                .accessTokenValiditySeconds(72000)
//                // 可以访问资源列表
//                .resourceIds("res1")
//                //授权码、密码授权模式和刷新令牌
//                .authorizedGrantTypes(
//                        // 授权码
//                        "authorization_code",
//                        // 客户端验证
//                        "client_credentials",
//                        // 刷新
//                        "refresh_token",
//                        // 密码
//                        "password",
//                        // 隐式
//                        "implicit")
//                // 授权范围 all read
//                .scopes( "all")
//                // 跳转到授权页面
//                .autoApprove(false)
//                // 跳转回调地址
//                .redirectUris("http://www.baidu.com")
//        //.and().withClient("other").secret(new BCryptPasswordEncoder().encode("internet_plus"))
//        ;
    }

    /**
     * 配置令牌访问端点和令牌服务
     * 申请令牌url
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 密码模
        endpoints.authenticationManager(authenticationManager)
                // 授权码
                .authorizationCodeServices(authorizationCodeServices)
                // 令牌
                .tokenServices(tokenServices())
                // post 提交
                .allowedTokenEndpointRequestMethods(HttpMethod.POST)
        ;
        //.userDetailsService(userDetailsService);
    }
}
